package com.suning.sawp.service.impl.bind;

import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.annotation.Resource;

import org.apache.commons.collections.CollectionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.suning.framework.dal.client.DalClient;
import com.suning.sawp.constants.ErrorCodeConstants;
import com.suning.sawp.constants.LoggerConstants;
import com.suning.sawp.dto.common.QueryResult;
import com.suning.sawp.dto.common.ReturnMsg;
import com.suning.sawp.dto.mainpush.StoreManDto;
import com.suning.sawp.dto.precharge.CommonRtn;
import com.suning.sawp.intf.bind.BindConstants;
import com.suning.sawp.intf.bind.BindDeviceService;
import com.suning.sawp.intf.bind.dto.ApplyAndBindRtnDto;
import com.suning.sawp.intf.bind.dto.BindDeviceInfoDto;
import com.suning.sawp.intf.bind.dto.BindOperationDto;
import com.suning.sawp.intf.bind.dto.BindRecordDto;
import com.suning.sawp.intf.bind.dto.BindUnlockApplyDto;
import com.suning.sawp.intf.dao.StoreManLoginLogDaoService;
import com.suning.sawp.po.StoreManLoginLog;
import com.suning.sawp.service.util.ConfigUtil;
import com.suning.sawp.service.util.DateUtils;
import com.suning.sawp.service.util.RedisCacheUtils;
import com.suning.vgs.follow.remote.intf.StoreManRemoteService;
import com.suning.vgs.follow.remote.store.StoreManBaseDto;

/**
 * 
 * 设备绑定服务类<br>
 * 〈功能详细描述〉
 *
 * @author 17061157
 * @see [相关类/方法]（可选）
 * @since [产品/模块版本] （可选）
 */
@Service
public class BindDeviceServiceImpl implements BindDeviceService {

	private static final Logger LOGGER = LoggerFactory.getLogger(LoggerConstants.SAWP_SERVICE);
	
	private static final int CHANGES_THEN_LOCK = Integer.parseInt(ConfigUtil.getConfig("/config/sawp/bind", "changesThenLock", "3"));
	
	private static final String STAFF_DEVICE_INFO = "com.suning.sawp:validDeviceId:staffId:";
	
	@Resource
	StoreManLoginLogDaoService storeManLoginLogDao;
	
	@Resource
	StoreManRemoteService storeManRemoteService;
	
	@Resource
	DalClient dalClient;
	
	@Autowired
	private RedisCacheUtils redisClient;

	@Override
	public boolean staffIsLock(String staffId, String deviceId) {
		Map<String, Object> queryMap = new HashMap<String, Object>();
		queryMap.put("staffId", staffId);
		queryMap.put("deviceId", deviceId);
		queryMap.put("changes", CHANGES_THEN_LOCK);

		Map<String, Object> countMap = dalClient.queryForMap("BIND_DEVICE.DECIDE_LOCK_STATUS", queryMap);
		int count = ((Long) countMap.get("num")).intValue();
		return count > 0;
	}

	@Override
	public BindRecordDto queryCurrBindInfo(String staffId) {
		Map<String, Object> queryMap = new HashMap<String, Object>();
		queryMap.put("staffId", staffId);
		
		BindRecordDto dto = dalClient.queryForObject("BIND_DEVICE.QUERY_CURR_BIND_INFO", queryMap, BindRecordDto.class);
		return dto;
	}
	
	@Override
	public boolean queryBindsIn7days(String staffId) {
		Map<String, Object> queryMap = new HashMap<String, Object>();
		queryMap.put("staffId", staffId);

		Map<String, Object> countMap = dalClient.queryForMap("BIND_DEVICE.QUERY_BINDS_IN_7DAYS", queryMap);
		int count = ((Long) countMap.get("num")).intValue();
		return count >= CHANGES_THEN_LOCK;
	}
	
	@Override
	public BindUnlockApplyDto queryUnlockApplyInfo(String staffId) {
		Map<String, Object> queryMap = new HashMap<String, Object>();
		queryMap.put("staffId", staffId);
		
		BindUnlockApplyDto info = dalClient.queryForObject("BIND_DEVICE.QUERY_UNLOCK_APPLY", 
				queryMap, BindUnlockApplyDto.class);
		return info;
	}

	@Override
	public List<BindRecordDto> queryLatestThreeBindInfo(String staffId) {
		Map<String, Object> queryMap = new HashMap<String, Object>();
		queryMap.put("staffId", staffId);
		
		List<BindRecordDto> list = dalClient.queryForList("BIND_DEVICE.QUERY_LATEST_BIND_INFO", 
				queryMap, BindRecordDto.class);
		return list;
	}

	@Override
	public ReturnMsg<CommonRtn> unlockApply(String staffId, String deviceId, 
			String deviceName, String applyReason, String ip) {
		ReturnMsg<CommonRtn> ret = new ReturnMsg<CommonRtn>();
		
		// 当前用户是否在白名单
		if (queryWhitelistStatus(staffId)) {
			ret.setError(ErrorCodeConstants.ERR_0051, ErrorCodeConstants.ERR_MAP);
		} else if(!staffIsLock(staffId, deviceId)) {
			// 帐号不在锁定状态 
			ret.setError(ErrorCodeConstants.ERR_0054, ErrorCodeConstants.ERR_MAP);
		} else if (alreadyApplyUnlock(staffId)) {
			// 已经申请了解锁
			ret.setError(ErrorCodeConstants.ERR_0053, ErrorCodeConstants.ERR_MAP);
		} else {
			Map<String, Object> paramMap = new HashMap<String, Object>();
			paramMap.put("ip", ip);
			paramMap.put("staffId", staffId);
			paramMap.put("deviceId", deviceId);
			paramMap.put("deviceName", deviceName);
			paramMap.put("applyReason", applyReason);

			dalClient.execute("BIND_DEVICE.APPLY_UNLOCK", paramMap);
		}
		return ret;
	}

	@Override
	public ReturnMsg<QueryResult<BindDeviceInfoDto>> queryBindInfoList(Map<String, Object> queryMap, Integer pageNo,
			Integer pageSize) {
		ReturnMsg<QueryResult<BindDeviceInfoDto>> returnMsg = new ReturnMsg<QueryResult<BindDeviceInfoDto>>();
		queryMap.put("startIndex", pageSize * (pageNo - 1));
		queryMap.put("maxCount", pageSize);
		queryMap.put("changes", CHANGES_THEN_LOCK);

		QueryResult<BindDeviceInfoDto> queryResult = new QueryResult<BindDeviceInfoDto>();

		Map<String, Object> countMap = dalClient.queryForMap("BIND_DEVICE.QUERY_BIND_DEVICE_LIST_COUNT", queryMap);
		int count = ((Long) countMap.get("num")).intValue();

		if (count > 0) {
			List<BindDeviceInfoDto> list = dalClient.queryForList("BIND_DEVICE.QUERY_BIND_DEVICE_LIST", queryMap,
					BindDeviceInfoDto.class);
			for(BindDeviceInfoDto dto : list) {
				// 查询最后一次登录时间
				List<StoreManLoginLog> logs = storeManLoginLogDao.queryLoginLogs(dto.getStaffId(), 0, 1);
                if (CollectionUtils.isNotEmpty(logs)) {
                	dto.setLoginTime(DateUtils.getDateStrByFormat(
                            logs.get(0).getLoginTime(), DateUtils.ACCURATE_MINUTES_PATTERN));
                }
			}
			queryResult.setRecords(list);
		}

		queryResult.setTotalSize(count);
		returnMsg.setData(queryResult);
		return returnMsg;
	}

	@Override
	public ReturnMsg<QueryResult<BindOperationDto>> queryBindOperationHis(String staffId) {
		ReturnMsg<QueryResult<BindOperationDto>> returnMsg = new ReturnMsg<QueryResult<BindOperationDto>>();
		QueryResult<BindOperationDto> queryResult = new QueryResult<BindOperationDto>();

		Map<String, Object> queryMap = new HashMap<String, Object>();
		queryMap.put("staffId", staffId);

		List<BindOperationDto> list = dalClient.queryForList("BIND_DEVICE.QUERY_BIND_OPERATE_HISTORY", queryMap,
				BindOperationDto.class);

		queryResult.setRecords(list);
		returnMsg.setData(queryResult);

		return returnMsg;
	}

	@Override
	public ReturnMsg<QueryResult<BindRecordDto>> queryBindHistory(String staffId) {
		ReturnMsg<QueryResult<BindRecordDto>> returnMsg = new ReturnMsg<QueryResult<BindRecordDto>>();
		QueryResult<BindRecordDto> queryResult = new QueryResult<BindRecordDto>();

		Map<String, Object> queryMap = new HashMap<String, Object>();
		queryMap.put("staffId", staffId);

		List<BindRecordDto> list = dalClient.queryForList("BIND_DEVICE.QUERY_BIND_RECORD_HISTORY", queryMap,
				BindRecordDto.class);

		queryResult.setRecords(list);
		returnMsg.setData(queryResult);

		return returnMsg;
	}

	@Override
	public boolean queryWhitelistStatus(String staffId) {
		Map<String, Object> queryMap = new HashMap<String, Object>();
		queryMap.put("staffId", staffId);

		Map<String, Object> countMap = dalClient.queryForMap("BIND_DEVICE.QUERY_WHITELIST_STATUS", queryMap);
		int count = ((Long) countMap.get("num")).intValue();

		return count > 0;
	}

	@Override
	@Transactional
	public boolean addWhitelist(String staffId, String operatorId, String operatorName) {
		Map<String, Object> paramMap = new HashMap<String, Object>();
		paramMap.put("staffId", staffId);
		paramMap.put("operatorId", operatorId);
		paramMap.put("operatorName", operatorName);

		int addWhite = dalClient.execute("BIND_DEVICE.ADD_WHITELIST", paramMap);

		paramMap.put("remark", null);
		paramMap.put("type", BindConstants.OP_ADD_WHITE);
		paramMap.put("isBind", BindConstants.OP_NO_BIND);
		paramMap.put("isBack", BindConstants.OP_IS_BACK);
		int addLog = dalClient.execute("BIND_DEVICE.ADD_BIND_OPERATE_LOG", paramMap);
		return addWhite == 1 && addLog == 1;
	}

	@Override
	@Transactional
	public boolean removeWhitelist(String staffId, String operatorId, String operatorName) {
		Map<String, Object> paramMap = new HashMap<String, Object>();
		paramMap.put("staffId", staffId);
		paramMap.put("operatorId", operatorId);
		paramMap.put("operatorName", operatorName);

		int removeWhite = dalClient.execute("BIND_DEVICE.REMOVE_WHITELIST", paramMap);

		paramMap.put("remark", null);
		paramMap.put("type", BindConstants.OP_REMOVE_WHITE);
		paramMap.put("isBind", BindConstants.OP_NO_BIND);
		paramMap.put("isBack", BindConstants.OP_IS_BACK);
		int removeLog = dalClient.execute("BIND_DEVICE.ADD_BIND_OPERATE_LOG", paramMap);
		return removeWhite == 1 && removeLog == 1;
	}

	@Override
	@Transactional
	public boolean UnlockLockedStaff(String staffId, String deviceId, String operatorId, String operatorName) {
		BindUnlockApplyDto unlockApplyDto = queryUnlockApplyInfo(staffId);
		
		Map<String, Object> paramMap = new HashMap<String, Object>();
		paramMap.put("staffId", staffId);
		paramMap.put("ip", unlockApplyDto.getIp());
		paramMap.put("deviceId", unlockApplyDto.getDeviceId());
		paramMap.put("deviceName", unlockApplyDto.getApplyDevice());

		// 更新绑定记录，将绑定设备更新为此申请解锁的设备
		int updateBind = dalClient.execute("BIND_DEVICE.UPDATE_BIND_DEVICE", paramMap);

		// 增加管理员解锁操作记录
		paramMap.put("operatorId", operatorId);
		paramMap.put("operatorName", operatorName);
		paramMap.put("remark", null);
		paramMap.put("type", BindConstants.OP_UNLOCK); // 解锁
		paramMap.put("isBind", BindConstants.OP_IS_BIND); // 是绑定操作
		paramMap.put("isBack", BindConstants.OP_IS_BACK); // 是后台操作
		int addLog = dalClient.execute("BIND_DEVICE.ADD_BIND_OPERATE_LOG", paramMap);
		
		// 删除此条解锁申请记录
		int deleteApply = dalClient.execute("BIND_DEVICE.DELETE_UNLOCK_APPLY", paramMap);
		
		// 将此帐号的绑定记录都标注为"已解锁", 防止查询绑定信息时仍然显示为锁定状态
		int updateUnlock = dalClient.execute("BIND_DEVICE.UPDATE_UNLOCK_STATUS", paramMap);
		
		// 处理远程绑定关系
		StoreManBaseDto baseDto = storeManRemoteService.queryStoreManBaseInfoByStaffId(staffId);
        if (null != baseDto) {
            // 清除原有的设备ID
            LOGGER.info("System.validDeviceSms deviceId has bind romve deviceId={}", deviceId);
            unBindStaffIdDevice(baseDto.getStaffId(), baseDto.getDeviceId(), baseDto.getDeviceName());
        }
        // 绑定新的设备ID
        bindStaffIdDevice(staffId, unlockApplyDto.getDeviceId(), unlockApplyDto.getApplyDevice());

		return updateBind == 1 && deleteApply == 1 && addLog == 1 && updateUnlock > 0;
	}

	/**
     * 功能描述: 远程服务解除绑定设备ID<br>
     */
    public void unBindStaffIdDevice(String staffId, String deviceId, String deviceName) {
     // 清除此设备绑定关系
        storeManRemoteService.updateStoreManDeviceId(staffId, null, null, null);
        // 清除redis中此对绑定关系
        final String deviceIdkey = STAFF_DEVICE_INFO + staffId;
        redisClient.del(deviceIdkey);
        Object[] args = {staffId, deviceId, deviceName};
        LOGGER.info("validDeviceSms remove device bind staffId:{}, deviceId:{}, deviceName:{}", args);
        
    }
	
    /**
     * 功能描述: 远程服务绑定设备ID<br>
     */
    public void bindStaffIdDevice(String staffId, String deviceId, String deviceName) {
        // 更新此对设备绑定关系
        storeManRemoteService.updateStoreManDeviceId(staffId, deviceId, deviceName, new Date());
        // 清除redis中现有的工号-设备ID绑定关系
        final String key = STAFF_DEVICE_INFO + staffId;
        redisClient.del(key);
        
        Object[] args = {staffId, deviceId, deviceName};
        LOGGER.info("validDeviceSms bind device staffId:{}, deviceId:{}, deviceName:{}", args);
        
    }
    
	@Override
	@Transactional
	public boolean RejectUnlockedApply(String staffId, String deviceId, String reason, String operatorId, String operatorName) {
		Map<String, Object> paramMap = new HashMap<String, Object>();
		paramMap.put("staffId", staffId);
//		paramMap.put("deviceId", deviceId);

		paramMap.put("operatorId", operatorId);
		paramMap.put("operatorName", operatorName);
		paramMap.put("remark", reason); // 驳回理由
		paramMap.put("type", BindConstants.OP_REJECT); // 驳回
		paramMap.put("isBind", BindConstants.OP_NO_BIND); // 不是绑定操作
		paramMap.put("isBack", BindConstants.OP_IS_BACK); // 是后台操作
		// 增加管理员解锁操作记录
		int addLog = dalClient.execute("BIND_DEVICE.ADD_BIND_OPERATE_LOG", paramMap);
		
		// 删除此条解锁申请记录
		int deleteApply = dalClient.execute("BIND_DEVICE.DELETE_UNLOCK_APPLY", paramMap);

		return deleteApply == 1 && addLog == 1;
	}

	@Override
	@Transactional
	public boolean addBindInfo(String staffId, StoreManDto staffInfo, String deviceId, 
			String deviceName, String opStaffId, String opStaffName, int opType, String ip) {
		Map<String, Object> paramMap = new HashMap<String, Object>();
		paramMap.put("staffId", staffId);
		paramMap.put("deviceId", deviceId);
		paramMap.put("deviceName", deviceName);
		paramMap.put("staffName", staffInfo.getStaffName());
		paramMap.put("positionName", staffInfo.getPositionName());
		paramMap.put("ip", ip);
		
		paramMap.put("storeCode", staffInfo.getStoreCode());
		paramMap.put("storeName", staffInfo.getStoreName());
		paramMap.put("branchCode", staffInfo.getBranchCode());
		paramMap.put("branchName", staffInfo.getBranchName());
		paramMap.put("regionCode", staffInfo.getSaleRegionCode());
		paramMap.put("regionName", staffInfo.getRegionName());
		
		paramMap.put("operatorId", opStaffId);
		paramMap.put("operatorName", opStaffName);
		paramMap.put("type", opType); // 绑定类型
		paramMap.put("isBind", BindConstants.OP_IS_BIND); // 是绑定操作
		paramMap.put("isBack", opType == BindConstants.OP_SLEF_BIND ? 
				BindConstants.OP_NO_BACK : BindConstants.OP_IS_BACK); // 是否后台操作
		try {
			int addBind = dalClient.execute("BIND_DEVICE.ADD_BIND_INFO", paramMap);
			int addLog = dalClient.execute("BIND_DEVICE.ADD_BIND_OPERATE_LOG", paramMap);
			LOGGER.info("addBindInfo Success: staffId:{}, deviceId:{},deviceName:{},staffName:{},positionName:{}",
					staffId, deviceId, deviceName, staffInfo.getStaffName(), staffInfo.getPositionName());
			return addBind > 0 && addLog == 1;
		} catch (Exception e) {
			LOGGER.error("addBindInfo fail: ", e);
			return false;
		}
	}

	@Override
	public boolean deleteBindInfo(String staffId) {
		Map<String, Object> paramMap = new HashMap<String, Object>();
		paramMap.put("staffId", staffId);
		try {
			int deleteBind = dalClient.execute("BIND_DEVICE.DELETE_BIND_INFO", paramMap);
			return deleteBind > 0;
		} catch (Exception e) {
			LOGGER.error("deleteBindInfo fail: ", e);
			return false;
		}
	}

	@Override
	public boolean alreadyApplyUnlock(String staffId) {
		Map<String, Object> queryMap = new HashMap<String, Object>();
		queryMap.put("staffId", staffId);

		Map<String, Object> countMap = dalClient.queryForMap("BIND_DEVICE.ALREADY_APPLY_UNLOCK", queryMap);
		int count = ((Long) countMap.get("num")).intValue();
		return count > 0;
	}

	@Override
	public ApplyAndBindRtnDto queryRejectInfo(String staffId) {
		Map<String, Object> queryMap = new HashMap<String, Object>();
		queryMap.put("staffId", staffId);
		ApplyAndBindRtnDto rejectDto = dalClient.queryForObject("BIND_DEVICE.QUERY_REJECT_INFO", queryMap, ApplyAndBindRtnDto.class);
		dalClient.execute("BIND_DEVICE.CLEAN_REJECT_INFO", queryMap);
		return rejectDto;
	}

}
